package com.huitone.smspfm.socket.core.net;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.SocketException;
import java.util.Set;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.huitone.smspfm.socket.protocol.sgip.constant.CommandID;
import com.huitone.smspfm.socket.protocol.sgip.message.Message;
import com.huitone.smspfm.socket.protocol.sgip.message.msgbody.BindResp;
import com.huitone.smspfm.socket.protocol.sgip.message.msghead.Head;

/**
 * 套接字服务类
 * @author ybliang
 */
public class ExtServerSocket extends ServerSocket {
	
	private static final Logger logger = LogManager.getLogger(ExtServerSocket.class);
	
	/**
	 * 套接字校验器
	 */
	//private Validator connChecker = null; 
	
	/**
	 * 套接字管理器
	 */
	//private ExtSocketManager socketManager = null;
	
	/**
	 * 需要拦截的IP黑名单
	 */
	private Set<String> blackIps = null;
	
	/**
	 * 需要忽略的IP
	 */
	private Set<String> ignoreIps = null;
	
	public ExtServerSocket(int port) throws IOException {
		super(port);
	}

	/**
	 * 获取套接字
	 */
	public ExtSocket accept() throws IOException {
		
		if (isClosed())
            throw new SocketException("Socket is closed");
        if (!isBound())
            throw new SocketException("Socket is not bound yet");
        
        ExtSocket socket = new ExtSocket();
        
        implAccept(socket);
        
        // 打印IP地址
        InetAddress inetAddress = socket.getInetAddress();
        String hostAddress = inetAddress.getHostAddress();
        
        if (blackIps != null && !blackIps.isEmpty()) {
        	if (blackIps.contains(hostAddress)) {
				socket.close();
				logger.warn("监听到一条连接请求,请求源IP:[" + hostAddress+ "],该源IP在黑名单中!");
            	return null;
        	}
        }
        
        if (ignoreIps != null && !ignoreIps.isEmpty()) {
        	if (ignoreIps.contains(hostAddress)) {
				socket.close();
				logger.debug("监听到一条连接请求,请求源IP:[" + hostAddress+ "],该源IP在忽略名单中!");
            	return null;
        	}
        }
        
        logger.info("监听到一条连接请求,请求源IP:[" + hostAddress+ "]");
        
        return socket;
        
       /* if (connChecker != null) {
        	
        	System.out.println("读取信息Start");
        	
        	Message message = socket.read();
        	
        	System.out.println("读取信息End");
        	
			Head head = (Head) message.getHead();
			
			if (head.getCommandID() == CommandID.SGIP_BIND) { 
				// 这是一条Bind请求
				Bind bind = (Bind) message.getBody();
				
				Result result = connChecker.verificate(bind);
				if (result != null) {
					if (result.isAccept()) {
						
						AccountInfo accountInfo = result.getAccountInfo();
						if (accountInfo == null) {
							accountInfo = new AccountInfo();
							accountInfo.setSrvNode(bind.getSrvNode());
							accountInfo.setLoginName(bind.getLoginName());
							accountInfo.setLoginPassword(bind.getLoginPassword());
							accountInfo.setLogin(true);
						}
						
						accountInfo.setInetAddress(inetAddress);
						
						socket.setAccountInfo(accountInfo);
						
						if (socketManager != null) {
							
			        		AddResult added = socketManager.add(socket);
			        		
			        		switch (added) {
							case AddSucc:
								logger.info("绑定成功"+accountInfo.toString());
								response(head, result.getErrorCode(), socket);
			        			return socket;
							case AddFail:
								logger.info("绑定失败,添加不成功" + accountInfo.toString());
								response(head, ErrorCode.CODE_15, socket);
								break;
								
							case MapNull:
								logger.info("绑定失败,添加不成功" + accountInfo.toString());
								response(head, ErrorCode.CODE_15, socket);
								break;
								
							case MaxPerSize:
								Integer integer = socketManager.getPersktsize().get(socket.getAccountInfo().toString());
								logger.warn("绑定失败,同一客户端套接字列表已满,最大可接受套接字连接数:" + ((integer == null) ? 0 : integer) +"," + accountInfo.toString());
								response(head, ErrorCode.CODE_13, socket);
								break;
								
							case MaxSize:
								logger.warn("绑定失败,套接字管理器已满,最大可接受套接字连接数:" + socketManager.getMaxSize() +"," + accountInfo.toString());
								response(head, ErrorCode.CODE_12, socket);
								break;
							}
			        		
			        		socket.close(); return null;
			        		
			        	} else {
			        		response(head, result.getErrorCode(), socket); return socket;
			        	}
					} else {
						response(head, result.getErrorCode(), socket); socket.close(); return null;
					}
				} else {
					throw new NullPointerException("Result is null");
				}
			} else {
				response(head, ErrorCode.CODE_16, socket);
				socket.close();
            	return null;
			}
        } else {
        	if (socketManager != null) {
        		socket.setAccountInfo(new AccountInfo());
        		AddResult added = socketManager.add(socket);
        		if (added == AddResult.AddSucc) {
        			return socket;
        		} else {
        			return null;
        		}
        	} else {
        		return socket;
        	}
        }*/
	}

	/*public Validator getConnChecker() {
		return connChecker;
	}

	public void setConnChecker(Validator connChecker) {
		this.connChecker = connChecker;
	}*/
	
	/**
	 * @param head 接收的消息头
	 * @param result 接收消息的处理结果
	 * @param outputStream 客户端输出流
	 * @return 发送响应是否成功了
	 */
	public boolean response(Head head, int result, ExtSocket socket) {
		
		boolean respResult = true;
		
		try {
			
			BindResp resp = BindResp.build(result);
			
			Head respHead = Head.build(resp.length(), CommandID.SGIP_BIND_RESP, head.getSerialNoPart1(), head.getSerialNoPart2(), head.getSerialNoPart3());
			
			socket.write(new Message(respHead, resp));
			
		} catch (Exception e) {
			respResult = false;
		}
		
		return respResult;
	}

	/*public ExtSocketManager getSocketManager() {
		return socketManager;
	}

	public void setSocketManager(ExtSocketManager socketManager) {
		this.socketManager = socketManager;
	}*/

	@Override
	public void close() throws IOException {
		super.close();
		/*if (socketManager != null) {
			socketManager.destory();
		}*/
	}

	public Set<String> getBlackIps() {
		return blackIps;
	}

	public void setBlackIps(Set<String> ips) {
		this.blackIps = ips;
	}

	public Set<String> getIgnoreIps() {
		return ignoreIps;
	}

	public void setIgnoreIps(Set<String> ips) {
		this.ignoreIps = ips;
	}
}
